﻿//由W意波(LuoJun)编写，除了对左右值引用类型的const、volite、pointer判定外，其它判定结果跟标准库一致
#ifndef LK_TYPE_
#define LK_TYPE_
#include <vector>
namespace LK
{
	//声明PFunObjs
	namespace Functional { struct PFunObjs; }
	//记录类型通用函数数据
	struct CommonTypeFunctionInfoStruct
	{
		char const* Name;
		//类型大小
		index_t size;
		//构造方法
		void(*DefaultConstructMethod)(void*);
		//析构方法
		void(*DeconstructMethod)(void*);
		//复制构造方法
		void(*CopyConstructMethod)(void*, const void*);
		//默认方法
		template<class T>static void DefDefaultConstructMethod(void* p) { placementnew((T*)p); }
		template<class T>static void DefCopyConstructMethod(void* pd, void const*ps) { placementnew((T*)pd, *(const T*)ps); }
		template<class T>static void DefDeconstructMethod(void* p) { ((T*)p)->T::~T(); }
		CommonTypeFunctionInfoStruct()//默认构造
		{
			CopyConstructMethod = NULL;
			DeconstructMethod = NULL;
			DefaultConstructMethod = NULL;
			size = 0;
		}
	};

	bool operator==(PType const&t1, PType const &t2);
	struct PType :PObject
	{
	private:static Mutex& GetMutexRef() { static Mutex mto; return mto; }
			template <class T>static inline PType MakeArray();
			template <class T>static inline PType MakeFunction();
			template <class T>static inline PType MakePointer();
			template <class T>static inline PType MakeNormal();
			template <class T>static inline PType MakeType(size_t extents);
	public:
		/**@brief 复制构造函数*/
		inline PType(PType const&t) { PObject::SetTo(t.PObject::GetPtr()); }
		/**@brief 从对象指针构造*/
		inline PType(Type const* p) { PObject::SetTo(StaticCastPointer(p)); }
		/**@brief 赋值*/
		inline PType& operator=(PType const&r) { PObject::SetTo(r.PObject::GetPtr()); return *this; }
		/**@brief 获取对象指针，并在对象指针为空时抛出异常*/
		inline Type* Ptr()const { return CheckPointer<Type>(PObject::GetPtr()); }
		/**@brief 获取对象指针*/
		inline Type* GetPtr()const { return CastPointer<Type>(PObject::GetPtr()); }
		/**@brief 重载operator->*/
		inline Type* operator->()const { return Ptr(); }
		/**@brief 检查对象引用计数如果不为1，则进行Clone。空引用将抛出异常*/
		inline Type* OnePtr() { Object* p = PObject::Ptr(); if (p->RefCount != 1) { PObject::SetTo(new Object()); p = PObject::Ptr(); } return CastPointer<Type>(p); }
		/**@brief 获取对象类型*/
		inline PType GetType()const;
		//默认构造空引用
		PType() {}
		/**
		@brief 添加类型信息*/
		static void AddTypeInfo();
		/**
		@brief 根据模板参数T生成类型信息*/
		template <class T>static inline PType Make();
		/**
		@brief 获取参数包内的所有参数，并打包为一个vector*/
		template <class T>static std::vector<PType> GetTypesFromArgs();
		template <class T>static PString GetStringFromArgs();
		/**
		@brief 获取全称*/
		PString GetFullName()const;
		/**
		@brief 获取名称*/
		PString GetName()const;
		/**
		@brief 获取全称*/
		PString GetFullName(PString str)const;
		/**
		@brief 获取名称*/
		PString GetName(PString str)const;
		/**
		@brief 是否可变参函数*/
		bool IsVaridicFunction()const;
		/**
		@brief 比较是否相等
		@note 不会抛出异常*/
		friend bool operator==(PType const&t1, PType const &t2);
		friend bool operator!=(PType const&t1, PType const &t2) { return !(t1 == t2); }
		/**
		@brief 比较大小关系，如果一方为NULL将抛出空指针异常*/
		friend bool operator>=(PType const&t1, PType const &t2) { return t1.CompareWith(t2) >= 0; }
		friend bool operator<=(PType const&t1, PType const &t2) { return t1.CompareWith(t2) <= 0; }
		friend bool operator>(PType const&t1, PType const &t2) { return t1.CompareWith(t2) > 0; }
		friend bool operator<(PType const&t1, PType const &t2) { return t1.CompareWith(t2) < 0; }
		/**
		@brief 从PObject类型动态转换到该类型，返回转换结果。如果转换失败，将抛出转换失败异常（需要Reflection支持）
		@note 该转换方式将会查找可能的二次转换链以进行模糊转换*/
		PObject DynamicConvertFrom(PObject const&from, index_t lv = 2)const;
		/**
		@brief 判断是否可从from类型转换到该类型
		@note 该转换方式将会查找可能的二次转换链以支持模糊转换*/
		bool CanDynamicConvertFrom(PType const&from, index_t lv = 2)const;
		/**
		@brief 比较两个类型信息的大小*/
		index_t CompareWith(PType const&)const;
		/**
		@brief 忽略attr限定进行比较*/
		index_t CompareWithoutExtents(PType const&t)const;
		/**
		@brief 获取关联类型ID*/
		index_t GetID()const;
		/**
		@brief 转变为指向该类型的指针类型，cnt表示添加的指针层级，默认为1;ar为外层限定特性，默认为0*/
		PType& SelfToPointer(index_t cnt = 1, size_t at = 0);
		/**
		@brief 转变为指向该类型的数组类型，cnt表示该维元素数*/
		PType& SelfToArray(index_t cnt);
		/**
		@brief 转变为该类型解引用的类型，cnt表示解引用次数，默认为1
		@note 该方法可以用于减小数组维数*/
		PType& SelfToPointed(index_t cnt = 1);
		/**
		@brief 设置函数类型
		@note types[0]表示返回值类型，types[1]开始表示参数类型。如果是可变参函数，最后一个元素请置空*/
		void SetFunctionArgs(std::vector<PType>types);
		/**
		@brief 是否函数*/
		bool IsFunction()const;
		/**
		@brief 是否是纯类型(指针、数组、函数、带限定者都不算纯类型)*/
		bool IsPureType()const;
		/**
		@brief 是否是纯类型的扩展*/
		bool IsPureTypeIgnoreExtents()const;
		/**
		@brief 是否是数组类型（忽略最外层引用、const、volatile特性）*/
		bool IsArray()const;
		/**
		@brief 是否是指针类型（忽略最外层引用、const、volatile特性）*/
		bool IsPointer()const;
		/**
		@brief 是否是const*/
		bool IsConst()const;
		/**
		@brief 是否是volatile*/
		bool IsVolatile()const;
		/**
		@brief 是否是左值引用*/
		bool IsLValueReference()const;
		/**
		@brief 是否是右值引用*/
		bool IsRValueReference()const;
		/**
		@brief 是否是引用*/
		bool IsReference()const;
		/**
		@brief 获取数组维数*/
		index_t GetArrayLevel()const;
		/**
		@brief 获取数组指定维上的元素数，比如对于数组类型int[5][4]，传入参数为0时返回5，传入2时返回0*/
		index_t GetElementCount(index_t d)const;
		/**
		@brief 获取大小(如果是引用类型则返回指针大小)*/
		index_t GetSize()const;
		/**
		@brief 获取大小（忽略引用类型）*/
		index_t GetSizeIgnoreReference()const;
		/**
		@brief 判断该类型的原始类型是否从另一类型派生，或者两种类型相同(需要Reflection支持)*/
		bool IsDerivedFrom(PType const& t)const;
		/**
		@breif 对数据地址p使用该类型的默认构造函数构造*/
		void DefaultConstruct(void* p)const;
		/**
		@breif 对数据地址p使用该类型的析构函数析构*/
		void Deconstruct(void* p)const;
		/**
		@breif 使用数据地址ps的内容使用该类型的复制构造方法写到数据地址pd中*/
		void CopyConstruct(void* pd, void const*ps)const;
		/**
		@breif 对数据地址p使用该类型的默认构造函数构造（忽略引用特性）*/
		void DefaultConstructIgnoreReference(void* p)const;
		/**
		@breif 对数据地址p使用该类型的析构函数析构（忽略引用特性）*/
		void DeconstructIgnoreReference(void* p)const;
		/**
		@breif 使用数据地址ps的内容使用该类型的复制构造方法写到数据地址pd中（忽略引用特性）*/
		void CopyConstructIgnoreReference(void* po, void const*ps)const;
		/**
		@brief 同类型数据引用转换*/
		static PMObjects SameTypeReferenceConvert(PType const& to, PMObjects const& src);
		/**
		@brief 同类型数据引用转换*/
		static PMObjects SameTypeReferenceConvert(PType const& to, PObject const& src);
	};
	struct Type : ICloneables
	{
		/**
		@brief 获取Type类的类型信息*/
		virtual PType GetType()const;
		/**
		@brief 获取新的对象*/
		virtual Type* Clone()const;
		/**
		@brief operator&重载*/
		inline Type*operator&() { if (((Object*)this)->RefCount == 0)++((Object*)this)->RefCount; return this; }
		inline Type const*operator&()const { if (((Object*)this)->RefCount == 0)++((Object*)this)->RefCount; return this; }
		static std::vector<CommonTypeFunctionInfoStruct>& GetTypeCommonInfoRef();
	private:
		friend struct PType;
		static SpinMutex& GetMutexRef() { static SpinMutex mto; return mto; }
		//调用初始化函数（防止重复调用）
		static void CallAddTypeInfoFunction(void(*)());
		//判断两个type是否是指针而且可转换
		static bool IsPointerConvertible(Type const& from, Type const&to);
		template<class T>static long GetId1();
	public:
		/**
		@brief 获取本地唯一类型Id，每获取一次就+1，结果永远大于0*/
		static index_t GetLocalTypeId()
		{
			//前17个基本数据类型void,bool,s8,s16,i32,s32,s64,u8,u16,ui32,u32,u64,float,double,long double,char,wchar_t
			static index_t index = 17;
			return ++index;
		}
		/**
		@brief 获取动态唯一类型Id，每获取一次就-1，结果永远小于0*/
		static index_t GetDynamicTypeId()
		{
			static index_t index = 0;
			return --index;
		}
		/**
		@brief 获取类型T的ID，该方法线程安全
		@note 类型T必须是最原生类型，否则将无法编译通过*/
		template<class T>static inline typename UseIf<!::LK::IsFunction<T>::V&&!::LK::IsArray<T>::V&&
			!::LK::IsPointer<T>::V&&::LK::IsSame<typename ::LK::RemoveAllExtents<T>::T, T>::V,
			long>::T
			GetId() { return GetId1<T>(); }
		/**
		@brief 如果跟函数类型有关系，则表示函数的返回值类型和参数类型（可变参最后一个参数为空引用，而且可变参算一个参数）*/
		std::vector<PType>funArgs;
		/**
		@brief 数组和指针信息
		[x]表示指针层级时<0，且[x+n]用以记录const和volatile限定，[x+n+1]跟[x]相等；
		[x]表示数组时大于0，且[x+k]记录const和volatile限定(如果x+k在最末尾，则交给attr来记录)*/
		std::vector<index_t>props;
		/**
		@brief 记录最外层类型特性，包括引用、volatile、const等*/
		size_t attr;
		/**
		@brief 原始类型id*/
		index_t ID;
		/**
		@brief 默认构造函数，构造空类型*/
		Type() :funArgs(), props(), attr(0), ID(0) {}
		/**
		@brief 使用一个类型Id和最外层限定特性来构造*/
		Type(index_t id, size_t at = 0) :funArgs(), props(), attr(at), ID(id) {}
		/**
		@brief 析构函数*/
		~Type() {}
		/**
		@brief 转变为指向该类型的指针类型，cnt表示添加的指针层级，默认为1;ar为外层限定特性，默认为0*/
		Type& SelfToPointer(index_t cnt = 1, size_t at = 0);
		/**
		@brief 转变为指向该类型的数组类型，cnt表示该维元素数*/
		Type& SelfToArray(index_t cnt);
		/**
		@brief 转变为该类型解引用的类型，cnt表示解引用次数，默认为1
		@note 该方法可以用于减小数组维数*/
		Type& SelfToPointed(index_t cnt = 1);
		/**
		@brief 设置函数类型
		@note types[0]表示返回值类型，types[1]开始表示参数类型。如果是可变参函数，最后一个元素请置空*/
		void SetFunctionArgs(std::vector<PType>types);
		/**
		@brief 是否函数*/
		bool IsFunction()const { return funArgs.size() != 0 && props.size() == 0; }
		/**
		@brief 是否是纯类型(指针、数组、函数、带限定者都不算纯类型)*/
		bool IsPureType()const { return funArgs.size() == 0 && props.size() == 0 && attr == 0; }
		/**
		@brief 是否是纯类型，忽略扩展*/
		bool IsPureTypeIgnoreExtents()const { return funArgs.size() == 0 && props.size() == 0; }
		/**
		@brief 是否是数组类型（忽略最外层引用、const、volatile特性）*/
		bool IsArray()const { return props.size() > 0 && props.back() > 0; }
		/**
		@brief 是否是指针类型（忽略最外层引用、const、volatile特性）*/
		bool IsPointer()const { return props.size() != 0 && props.back() < 0; }
		/**
		@brief 是否是const*/
		bool IsConst()const { return attr&TypeExtents::Const; }
		/**
		@brief 是否是volatile*/
		bool IsVolatile()const { return (attr&TypeExtents::Volatile) != 0; }
		/**
		@brief 是否是左值引用*/
		bool IsLValueReference()const { return (attr&TypeExtents::LValueReference) != 0; }
		/**
		@brief 是否是右值引用*/
		bool IsRValueReference()const { return (attr&TypeExtents::RValueReference) != 0; }
		/**
		@brief 是否是引用*/
		bool IsReference()const { return IsLValueReference() || IsRValueReference(); }
		/**
		@brief 是否可变参函数*/
		bool IsVaridicFunction()const { return funArgs.size() != 0 && funArgs.back().IsNull(); }
		/**
		@brief 判断该类型的原始类型是否从另一类型派生，或者两种类型相同*/
		bool IsDerivedFrom(PType const& t)const;
		//动态类型转换（lv为0时进行基础转换，1进行精确转换，2进行模糊转换）
		PObject DynamicConvertFrom(PObject const& obj, index_t lv = 2)const;
		//判断是否可从from类型转换到该类型
		bool CanDynamicConvertFrom(PType const&, index_t lv = 2)const;
		/**
		@brief 获取数组维数*/
		index_t GetArrayLevel()const;
		/**
		@brief 获取数组指定维上的元素数，比如对于数组类型int[5][4]，传入参数为0时返回5，传入2时返回0*/
		index_t GetElementCount(index_t d)const;
		/**
		@brief 获取全称*/
		PString GetFullName(PString instr)const;
		/**
		@brief 获取名称*/
		PString GetName(PString instr)const;
		/**
		@brief 获取全称*/
		PString GetFullName()const;
		/**
		@brief 获取名称*/
		PString GetName()const;
		/**
		@brief 获取大小（如果为左值引用，则为指针大小）*/
		index_t GetSize()const { if (IsLValueReference() || funArgs.size() != 0 || props.size() != 0)return sizeof(void*); return GetTypeCommonInfoRef()[ID].size; }
		/**
		@brief 获取大小(忽略引用)*/
		index_t GetSizeIgnoreReference()const { if (funArgs.size() != 0 || props.size() != 0)return sizeof(void*); return GetTypeCommonInfoRef()[ID].size; }
		/**
		@brief 比较*/
		friend bool operator==(Type const&t1, Type const&t2) { return t1.ID == t2.ID&&t1.attr == t2.attr&&t1.props == t2.props&&t1.funArgs == t2.funArgs; }
		friend bool operator!=(Type const&t1, Type const&t2) { return !(t1 == t2); }
		/**
		@brief 比较两个类型信息的大小*/
		index_t CompareWith(PType const&)const;
		/**
		@brief 忽略attr限定进行比较*/
		index_t CompareWithoutExtents(PType const&t)const;
		/**
		@breif 对数据地址p使用该类型的默认构造函数构造*/
		void DefaultConstruct(void* p)const;
		/**
		@breif 对数据地址p使用该类型的析构函数析构*/
		void Deconstruct(void* p)const;
		/**
		@breif 使用数据地址ps的内容使用该类型的复制构造方法写到数据地址pd中*/
		void CopyConstruct(void* pd, void const*ps)const;
		/**
		@breif 对数据地址p使用该类型的默认构造函数构造（忽略引用特性）*/
		void DefaultConstructIgnoreReference(void* p)const;
		/**
		@breif 对数据地址p使用该类型的析构函数析构（忽略引用特性）*/
		void DeconstructIgnoreReference(void* p)const;
		/**
		@breif 使用数据地址ps的内容使用该类型的复制构造方法写到数据地址pd中（忽略引用特性）*/
		void CopyConstructIgnoreReference(void* po, void const*ps)const;
	};
	template <class T>std::vector<PType> PType::GetTypesFromArgs()
	{
		if (IsSame<::LK::VarArgsPack<>, T>::V)
			return std::vector<PType>();
		typedef typename ::LK::UseT<::LK::IsSame<::LK::VarArgsPack<>, T>::V, T, ::LK::VarArgsPack<void> >::T TT;
		std::vector<PType>tmp = PType::GetTypesFromArgs<typename ::LK::ArgRemoveAt<0, TT >::T >();
		tmp.insert(tmp.begin(), PType::Make<typename ArgT<0, TT>::T >());
		return tmp;
	}
	template <class T>inline PType PType::MakeType(size_t extents)
	{
		typedef typename UseT<::LK::IsArray<T>::V, wchar_t[2], T>::T AT;
		typedef typename UseT<::LK::IsFunction<T>::V, void(), T>::T FT;
		typedef typename UseT<::LK::IsPointer<T>::V, void*, T>::T PT;
		typedef typename UseT<!::LK::IsPointer<T>::V&&!::LK::IsFunction<T>::V&&!::LK::IsArray<T>::V, void, T>::T NT;
		static PType t;
		if (t.IsNull()) {
			GetMutexRef().Lock();
			if (t.IsNull())
			{
				if (::LK::IsArray<T>::V)t= MakeArray<AT>();
				else if (::LK::IsFunction<T>::V)t= MakeFunction<FT>();
				else if (::LK::IsPointer<T>::V)t= MakePointer<PT>();
				else t= MakeNormal<NT>();
			}
			GetMutexRef().UnLock();
		}
		if(extents==0&&!::LK::IsFunction<T>::V)return t;
		t.OnePtr()->attr = extents;
		return t;
	}
	template <class T>inline PType PType::Make()
	{
		return MakeType<typename RemoveAllExtents<T>::T>(ExtentsOf<T>::V);
	}
	template <class T>inline PType PType::MakeArray()
	{
		PType t = PType::Make<typename ::LK::IsArray<T>::T>();
		t.OnePtr()->SelfToArray(::LK::IsArray<T>::C);
		return t;
	}
	template <class T>inline PType PType::MakeFunction()
	{
		PType t = new Type();
		t.GetPtr()->SetFunctionArgs(PType::GetTypesFromArgs<typename ::LK::IsFunction<T>::T>());
		t.GetPtr()->ID = Type::GetId<typename ::LK::ArgT<1, typename ::LK::IsFunction<T>::T>::T>();
		if ((::LK::IsFunction<T>::type &::LK::TypeExtents::Variable) != 0)//可变参添加一个空参数
			t.GetPtr()->funArgs.push_back(PType());
		return t;
	}
	template <class T>inline PType PType::MakePointer()
	{
		PType t = PType::Make<typename ::LK::RemovePointer<T>::T>();
		t.OnePtr()->SelfToPointer();
		return t;
	}
	template <class T>inline PType PType::MakeNormal()
	{
		PType t = new Type(Type::GetId<T>());
		if (IsBaseOf<PObject, T>::V)//调用AddTypeInfo函数
		{
			typedef typename UseT<IsBaseOf<PObject, T>::V, PObject, T>::T TClass;
			Type::CallAddTypeInfoFunction(&TClass::AddTypeInfo);
		}
		return t;
	}
	inline PType Object::GetType()const { return PType::Make<PObject>(); }
	inline PType PObject::GetType()const { return Ptr()->GetType(); }
	inline PType ICloneables::GetType()const { return PType::Make<PCloneables>(); }
	inline PType PCloneables::GetType()const { return PObject::GetType(); }
	inline PType PMObjects::GetType()const { return PObject::GetType(); }
	inline PType PType::GetType()const { return PObject::GetType(); }
}
#endif
